package com.xaaef.authorize.server.controller;

import com.xaaef.authorize.common.domain.TokenValue;
import com.xaaef.authorize.common.exception.OAuth2Exception;
import com.xaaef.authorize.common.util.JsonResult;
import com.xaaef.authorize.common.util.JsonUtils;
import com.xaaef.authorize.common.util.SecurityUtils;
import com.xaaef.authorize.server.params.*;
import com.xaaef.authorize.server.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * All rights Reserved, Designed By www.xaaef.com
 * <p>
 * 授权认证 控制器
 * </p>
 *
 * @author Wang Chen Chen<932560435@qq.com>
 * @version 1.0.0
 * @date 2020/7/2314:02
 */


@Slf4j
@RestController
@AllArgsConstructor
public class AuthorizeController {

    private ClientAuthorizeService clientAuthorizeService;

    private PasswordAuthorizeService passwordAuthorizeService;

    private SmsAuthorizeService smsAuthorizeService;

    private CaptchaCodesService captchaCodesService;

    private TokenService tokenService;

    /**
     * 客户端模式
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("client")
    public JsonResult<String> client(@RequestBody @Validated ClientModeParam param, BindingResult br) {
        if (br.hasErrors()) {
            String message = br.getFieldError().getDefaultMessage();
            return JsonResult.fail(message);
        }
        log.debug("client param: {}", JsonUtils.toJson(param));
        try {
            var token = clientAuthorizeService.authorize(param);
            return JsonResult.success(token);
        } catch (OAuth2Exception e) {
            return JsonResult.error(e.getStatus(), e.getMessage());
        }
    }


    /**
     * 密码模式
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("password")
    public JsonResult<String> password(@RequestBody @Validated PasswordModeParam param, BindingResult br) {
        if (br.hasErrors()) {
            String message = br.getFieldError().getDefaultMessage();
            return JsonResult.fail(message);
        }
        log.debug("password param: {}", JsonUtils.toJson(param));
        try {
            var token = passwordAuthorizeService.authorize(param);
            return JsonResult.success(token);
        } catch (OAuth2Exception e) {
            return JsonResult.error(e.getStatus(), e.getMessage());
        }
    }


    /**
     * 发送 短信验证码
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("sms/send")
    public JsonResult<String> sendSms(@RequestBody @Validated SendSmsParam param, BindingResult br) {
        if (br.hasErrors()) {
            String message = br.getFieldError().getDefaultMessage();
            return JsonResult.fail(message);
        }
        log.debug("send sms param: {}", JsonUtils.toJson(param));
        try {
            String code = smsAuthorizeService.sendSms(param.getClientId(), param.getMobile());
            return JsonResult.success(null, code);
        } catch (OAuth2Exception e) {
            return JsonResult.error(e.getStatus(), e.getMessage());
        }
    }


    /**
     * 手机短信验证码 模式
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("sms")
    public JsonResult<String> sms(@RequestBody @Validated SmsModeParam param, BindingResult br) {
        if (br.hasErrors()) {
            String message = br.getFieldError().getDefaultMessage();
            return JsonResult.fail(message);
        }
        log.debug("sms param: {}", JsonUtils.toJson(param));
        try {
            var token = smsAuthorizeService.authorize(param);
            return JsonResult.success(token);
        } catch (OAuth2Exception e) {
            return JsonResult.error(e.getStatus(), e.getMessage());
        }
    }


    /**
     * 刷新 token
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("refresh")
    public JsonResult<String> refreshToken(@RequestHeader("RefreshToken") String refreshToken) {
        if (StringUtils.isBlank(refreshToken)) {
            return JsonResult.fail("请求头中没有 refresh_token 参数！");
        }
        try {
            var token = tokenService.refresh(refreshToken);
            return JsonResult.success(token);
        } catch (OAuth2Exception e) {
            return JsonResult.error(e.getStatus(), e.getMessage());
        }
    }


    /**
     * 退出登录
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @PostMapping("logout")
    public JsonResult<String> logout() {
        tokenService.logout();
        return JsonResult.success();
    }


    /**
     * 获取用户信息
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @GetMapping("loginInfo")
    public JsonResult<TokenValue> loginInfo() {
        return JsonResult.success(SecurityUtils.getTokenValue());
    }


    /**
     * 获取验证码，前端传入一个 key，根据key生成一个验证码。将key 和验证码的值 保存在 redis 中
     * 用户登录的时候，根据key获取到，生成验证码值 和 用户输入验证码的值 做一个比较。
     *
     * @author Wang Chen Chen<932560435@qq.com>
     * @date 2020/7/23 14:08
     */
    @GetMapping("/captcha/codes/{codeKey}")
    public void imageCaptchaCodes(@PathVariable String codeKey, HttpServletResponse response) throws IOException {
        // 设置响应的类型格式为图片格式
        response.setContentType("image/jpeg");
        // 禁止图像缓存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        BufferedImage image = captchaCodesService.randomImageVerifyCode(codeKey);
        // 获取 图片 验证码
        ImageIO.write(image, "JPEG", response.getOutputStream());
    }


}
